package net.cyndeline.componentSystem.movement

import net.cyndeline.entitySystem.AbstractEventHandlerSystem
import net.cyndeline.entitySystem.defaultImpl.Aspect
import net.cyndeline.events.movement.MovementEvent
import net.cyndeline.components.world.PositionComponent
import net.cyndeline.components.world.OnMapComponent
import net.cyndeline.entitySystem.{ Event, EntityRef }
import language.postfixOps
import net.cyndeline.components.objectProperties.ObstacleComponent
import com.escalatesoft.subcut.inject.BindingModule
import com.escalatesoft.subcut.inject.Injectable
import net.cyndeline.events.movement.Movement
import net.cyndeline.components.objectProperties.Obstacle
import net.cyndeline.components.world.OnMap
import net.cyndeline.components.world.Position
import net.cyndeline.events.gameplay.RetakeActionEvent
import net.cyndeline.events.gameplay.RetakeAction

/**
 * Cancels movement events that are attempted by an obstacle by moving to
 * a location that has another obstacle on it.
 */
class MovementObstacleCheckSystem(implicit val bindingModule: BindingModule) 
extends AbstractEventHandlerSystem(
    new Aspect().getAll(classOf[Position], classOf[OnMap]),
    classOf[Movement])
with Injectable {
  
  override def onEvent(event: Event, entity: EntityRef) = event match {
    case move: MovementEvent => checkObstacles(move, entity)
    case _ => {}
  }
  
  private def checkObstacles(event: MovementEvent, mover: EntityRef) {
    val mapInfo = mover.getComponent(classOf[OnMap]) get
    val tileGrid = mapInfo.map
    val stop = event.stop
    val tileContent = tileGrid.objectsAt(stop._1, stop._2)
	
		/* One obstacle can't move into another obstacle. */
		if (mover.hasComponent(classOf[Obstacle])) {
		  for (ent <- tileContent) {
		    if (ent.hasComponent(classOf[Obstacle])) {
		      val cancelEvent = injectOptional[RetakeActionEvent] getOrElse new RetakeAction()
		      mover.send(cancelEvent)
		      event.cancel
		      return
		    }
		  }  
		}
  }
}